﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace EasyLib.DataStructure
{
    public class One2ManyMap<TKey, UValue> : IDictionary<TKey, IList<UValue>>
    {
        private Dictionary<TKey, IList<UValue>> map = new Dictionary<TKey, IList<UValue>>();

        public bool TryGetValue(TKey key, out IList<UValue> value)
        {
            throw new NotImplementedException();
        }

        public IList<UValue> this[TKey key]
        {
            get { return (map[key]); }
            set { map[key] = value; }
        }

        public ICollection<TKey> Keys
        {
            get { throw new NotImplementedException(); }
        }

        public ICollection<IList<UValue>> Values
        {
            get { throw new NotImplementedException(); }
        }

        public void Add(TKey key, UValue item)
        {
            AddSingleMap(key, item);
        }
        public void Add(TKey key, IList<UValue> items)
        {
            foreach (UValue val in items)
                AddSingleMap(key, val);
        }
        public void Add(KeyValuePair<TKey, IList<UValue>> keyValuePair)
        {
            foreach (UValue val in keyValuePair.Value)
                AddSingleMap(keyValuePair.Key, val);
        }
        public void Clear()
        {
            map.Clear();
        }

        public bool Contains(KeyValuePair<TKey, IList<UValue>> item)
        {
            throw new NotImplementedException();
        }

        public void CopyTo(KeyValuePair<TKey, IList<UValue>>[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public int Count
        {
            get { return (map.Count); }
        }

        public bool IsReadOnly
        {
            get { throw new NotImplementedException(); }
        }

        public bool ContainsKey(TKey key)
        {
            return (map.ContainsKey(key));
        }

        public bool ContainsValue(UValue item)
        {
            if (item == null)
            {
                foreach (KeyValuePair<TKey, IList<UValue>> kvp in map)
                {
                    if (((List<UValue>)kvp.Value).Count == 0)
                    {
                        return (true);
                    }
                }
                return (false);
            }
            else
            {
                foreach (KeyValuePair<TKey, IList<UValue>> kvp in map)
                {
                    if (((List<UValue>)kvp.Value).Contains(item))
                    {
                        return (true);
                    }
                }
                return (false);
            }
        }
        IEnumerator<KeyValuePair<TKey, IList<UValue>>> IEnumerable<KeyValuePair<TKey,
                                       IList<UValue>>>.GetEnumerator()
        {
            return (map.GetEnumerator());
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return (map.GetEnumerator());
        }
        public bool Remove(TKey key)
        {
            return (RemoveSingleMap(key));
        }
        public bool Remove(KeyValuePair<TKey, IList<UValue>> keyValuePair)
        {
            return (Remove(keyValuePair.Key));
        }
        protected void AddSingleMap(TKey key, UValue item)
        {
            // Search for key in map Hashtable.
            if (map.ContainsKey(key))
            {
                // Add value to List in map.
                List<UValue> values = (List<UValue>)map[key];
                // Add this value to this existing key.
                values.Add(item);
            }
            else
            {
                if (item == null)
                {
                    // Create new key and mapping to an empty List.
                    map.Add(key, new List<UValue>());
                }
                else
                {
                    List<UValue> values = new List<UValue>();
                    values.Add(item);
                    // Create new key and mapping to its value.
                    map.Add(key, values);
                }
            }
        }
        protected bool RemoveSingleMap(TKey key)
        {
            if (this.ContainsKey(key))
            {
                // Remove the key from KeysTable.
                return (map.Remove(key));
            }
            else
            {
                throw (new ArgumentOutOfRangeException("key", key,
                        "This key does not exists in the map."));
            }
        }
    }
}
